package cn.ztf.zshop.sys.service.impl;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.ztf.zshop.common.exception.ZShopException;
import cn.ztf.zshop.common.utils.PageConverterVo;
import cn.ztf.zshop.security.admin.service.SecurityService;
import cn.ztf.zshop.sys.dao.SysDeptDao;
import cn.ztf.zshop.sys.dao.SysMenuDao;
import cn.ztf.zshop.sys.dao.SysRoleDao;
import cn.ztf.zshop.sys.dao.SysUserDao;
import cn.ztf.zshop.sys.dto.*;
import cn.ztf.zshop.sys.po.SysDept;
import cn.ztf.zshop.sys.po.SysUser;
import cn.ztf.zshop.sys.service.SysUserService;
import cn.ztf.zshop.sys.vo.LoginInfo;
import cn.ztf.zshop.sys.vo.SysDeptVo;
import cn.ztf.zshop.sys.vo.SysUserVo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFacade;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.List;
import java.util.Optional;

@Slf4j
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserDao, SysUser> implements SysUserService {
    private final MapperFacade mapperFacade;
    private final SysDeptDao sysDeptDao;

    private final SysRoleDao sysRoleDao;

    private final SysMenuDao sysMenuDao;

    private final SecurityService securityService;

    @Override
    public Page<SysUserVo> listPage(Page<SysUser> page) {
        Page<SysUser> userPage = lambdaQuery().page(page);
        Page<SysUserVo> voPage = PageConverterVo.converterPage(userPage, SysUserVo.class, ((sysUser, sysUserVo) -> {
            SysDept sysDept = sysDeptDao.selectById(sysUser.getDeptId());
            SysDeptVo deptVo = mapperFacade.map(sysDept, SysDeptVo.class);
            sysUserVo.setSysDeptVo(deptVo);
            return sysUserVo;
        }));
        return voPage;
    }

    @Override
    public SysUserVo getSysUserById(Long id) {
        Optional<SysUser> userOptional = lambdaQuery().eq(SysUser::getUserId, id).oneOpt();
        SysUserVo userVo = userOptional.map(e -> {
            SysUserVo sysUserVo = mapperFacade.map(e, SysUserVo.class);
            SysDept sysDept = sysDeptDao.selectById(e.getDeptId());
            SysDeptVo deptVo = mapperFacade.map(sysDept, SysDeptVo.class);
            sysUserVo.setSysDeptVo(deptVo);

            List<Long> roleIds = sysRoleDao.findRoleByUserId(sysUserVo.getUserId());
            sysUserVo.setRoleIds(roleIds);
            return sysUserVo;
        }).orElse(null);
        return userVo;
    }

    @Override
    public void editInfo(SysUserInfoDto sysUserInfoDto) {
        // 获取登录id
        long loginId = StpUtil.getLoginIdAsLong();
        boolean update = lambdaUpdate().eq(SysUser::getUserId, loginId)
                .set(SysUser::getMobile, sysUserInfoDto.getMobile())
                .set(SysUser::getEmail, sysUserInfoDto.getEmail())
                .set(SysUser::getUsername, sysUserInfoDto.getUsername()).update();
    }

    @Override
    public void updatePassword(SysUserPasswordDto sysUserPasswordDto) {
        long loginId = StpUtil.getLoginIdAsLong();
        SysUser sysUser = lambdaQuery().eq(SysUser::getUserId, loginId).one();
        // 使用盐加密判断
        boolean checkpw = DigestUtil.bcryptCheck(sysUserPasswordDto.getOldPassword(), sysUser.getPassword());
        if (checkpw) {
            throw new ZShopException("密码不正确");
        }
        if (sysUserPasswordDto.getOldPassword().equals(sysUserPasswordDto.getNewPassword())) {
            throw new ZShopException("新密码不能和旧密码相同");
        }
        // 生成盐加密密码
        String hashpwPassword = DigestUtil.bcrypt(sysUserPasswordDto.getNewPassword());
        boolean update = lambdaUpdate().eq(SysUser::getUserId, loginId).set(SysUser::getPassword, hashpwPassword).update();
    }

    @Transactional
    @Override
    public void create(SysUserDto sysUserDto) {
        SysUser sysUser = mapperFacade.map(sysUserDto, SysUser.class);
        //TODO 设置当前登录用户id,应该设置默认密码
        long loginId = StpUtil.getLoginIdAsLong();
        sysUser.setCreateUserId(loginId);
        // 插入用户数据
        int insert = baseMapper.insert(sysUser);
        // 插入用户角色关联表
        if (!ObjectUtils.isEmpty(sysUserDto.getRoleIds())) {
            baseMapper.createSysUserRole(sysUserDto.getRoleIds(), sysUser.getUserId());
        }
        log.info("系统用户添加成功数量:{}", insert);
    }

    @Transactional
    @Override
    public void edit(SysUserDto sysUserDto) {
        //查询此用户id的会话,如果存在,则删除用户的角色缓存,这里必须先删除缓存,否则会出现脏数据
        SaSession saSession = StpUtil.getSessionByLoginId(sysUserDto.getUserId().toString(),false);
        if (!ObjectUtils.isEmpty(saSession)){
            saSession.delete("role:List");
        }
        // 删除用户角色的关联表
        baseMapper.deleteSysUserRole(sysUserDto.getUserId());
        if (!ObjectUtils.isEmpty(sysUserDto.getRoleIds())) {
            // 插入关联表数据
            baseMapper.createSysUserRole(sysUserDto.getRoleIds(), sysUserDto.getUserId());
        }
        SysUser sysUser = mapperFacade.map(sysUserDto, SysUser.class);
        // 修改用户信息
        baseMapper.updateById(sysUser);
    }

    @Transactional
    @Override
    public void delete(Long id) {
        SaSession saSession = StpUtil.getSessionByLoginId(id.toString(), false);
        if (!ObjectUtils.isEmpty(saSession)) {
            StpUtil.logout(id);
        }
        // 删除用户角色关联表数据
        baseMapper.deleteSysUserRole(id);
        // 再删除用户信息
        baseMapper.deleteById(id);
    }

    @Override
    public LoginInfo userLogin(UserLoginDto userLoginDto) {
        securityService.verification(userLoginDto.getCaptchaVO());
        SysUser user = lambdaQuery().eq(SysUser::getUsername, userLoginDto.getUsername()).one();
        if (ObjectUtils.isEmpty(user)) {
            throw new ZShopException("用户名不存在");
        }
        boolean check = DigestUtil.bcryptCheck(userLoginDto.getPassword(), user.getPassword());
        if (!check) {
            throw new ZShopException("密码错误");
        }
        StpUtil.login(user.getUserId());
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        return LoginInfo.builder()
                .token(tokenInfo.getTokenValue())
                .sysUserVo(mapperFacade.map(user, SysUserVo.class))
                .build();
    }

    @Override
    public void userLogout() {
        StpUtil.logout();
    }

    @Override
    public SysUserVo getByUsername(String username) {
        SysUser sysUser = lambdaQuery().eq(SysUser::getUsername, username).one();
        if (!ObjectUtils.isEmpty(sysUser)) {
            return mapperFacade.map(sysUser, SysUserVo.class);
        }
        return null;
    }

    @Override
    public List<String> getPermissionByUserId(Long id) {
        List<String> permissions = sysMenuDao.getPermissionByUserId(id);
        return permissions;
    }


    @Override
    public void userRegister(SysUserRegisterDto sysUserRegisterDto) {
        if (!sysUserRegisterDto.getPassword().equals(sysUserRegisterDto.getConfirmPassword())){
            throw new ZShopException("两次密码不一致");
        }
        SysUser sysUser = mapperFacade.map(sysUserRegisterDto, SysUser.class);
        // 生成盐加密密码
        String hashpwPassword = DigestUtil.bcrypt(sysUserRegisterDto.getPassword());
        sysUser.setPassword(hashpwPassword);
        // 插入用户数据
        int insert = baseMapper.insert(sysUser);
    }
}
